/*
 * Copyright 2008-2023 dexian.vip. All rights reserved.
 * Support: http://www.dexian.vip
 * License: http://www.dexian.vip/license
 */

package vip.dexian.admin.service.impl;

import vip.dexian.admin.dto.AdminDTO;
import vip.dexian.admin.dto.AdminPrincipal;
import vip.dexian.admin.service.OnlineAdminService;
import vip.dexian.common.query.Page;
import vip.dexian.common.utils.NumberUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.function.Predicate;

/**
 * 在线管理员管理
 *
 * @author 挺好的 2023年06月06日 17:28
 */
@Service ("onlineAdminServiceImpl")
@Transactional (propagation = Propagation.NOT_SUPPORTED)
@Lazy
public class OnlineAdminServiceImpl implements OnlineAdminService {

    /**
     * session 管理
     */
    @Autowired
    private SessionRegistry sessionRegistry;

    /**
     * 填充是否在线
     *
     * @param page
     *         管理员DTO
     */
    @Override
    public void fillOnline (Page <AdminDTO> page) {
        for (AdminDTO adminDTO : page.getContent()) {
            boolean isOnline = this.isOnline(adminDTO.getId());
            adminDTO.setIsOnline(isOnline);
        }
    }

    /**
     * 根据角色标识{@link vip.dexian.admin.entity.Role#getIdentity()}，踢出管理员
     *
     * @param role
     *         角色名称
     */
    @Override
    public void logoutByRole (String role) {
        if (StringUtils.isEmpty(role)) {
            return;
        }

        List <Object> adminPrincipals = this.sessionRegistry.getAllPrincipals();

        for (Object obj : adminPrincipals) {
            if (obj instanceof AdminPrincipal adminPrincipal) {

                boolean isMatch = adminPrincipal.getAuthorities().stream().anyMatch(
                        (Predicate <GrantedAuthority>) grantedAuthority -> grantedAuthority.getAuthority()
                                .equals(role));

                if (isMatch) {
                    this.removeSession(adminPrincipal);
                }
            }
        }

    }

    /**
     * 根据用户名踢出管理员
     *
     * @param username
     *         用户名
     */
    @Override
    public void logoutByUsername (String username) {
        if (StringUtils.isEmpty(username)) {
            return;
        }

        List <Object> adminPrincipals = this.sessionRegistry.getAllPrincipals();

        for (Object obj : adminPrincipals) {
            if (obj instanceof AdminPrincipal adminPrincipal) {

                boolean isMatch = adminPrincipal.getUsername().equals(username);

                if (isMatch) {
                    this.removeSession(adminPrincipal);
                }
            }
        }
    }


    /**
     * 根据id强制踢出用户
     *
     * @param id
     *         用户id
     */
    @Override
    public void logoutById (Long id) {
        if (!NumberUtils.isPositive(id)) {
            return;
        }

        List <Object> adminPrincipals = this.sessionRegistry.getAllPrincipals();

        for (Object obj : adminPrincipals) {
            if (obj instanceof AdminPrincipal adminPrincipal) {

                boolean isMatch = NumberUtils.equals(adminPrincipal.getId(), id);
                if (isMatch) {
                    this.removeSession(adminPrincipal);
                }
            }
        }
    }

    /**
     * 清空全部session
     */
    @Override
    public void clear () {
        List <Object> adminPrincipals = this.sessionRegistry.getAllPrincipals();

        for (Object obj : adminPrincipals) {
            if (obj instanceof AdminPrincipal adminPrincipal) {
                this.removeSession(adminPrincipal);
            }
        }
    }

    /**
     * 移除session
     *
     * @param principal
     */
    private void removeSession (Object principal) {
        List <SessionInformation> sessionInformationList = this.sessionRegistry.getAllSessions(principal, false);

        for (SessionInformation sessionInformation : sessionInformationList) {
            sessionInformation.expireNow();
        }
    }

    /**
     * @param id
     *         管理员id
     *
     * @return 是否在线
     */
    private boolean isOnline (Long id) {
        List <Object> adminPrincipals = this.sessionRegistry.getAllPrincipals();

        for (Object obj : adminPrincipals) {
            if (obj instanceof AdminPrincipal adminPrincipal) {

                if (!NumberUtils.equals(id, adminPrincipal.getId())) {
                    continue;
                }

                List <SessionInformation> sessionInformationList = this.sessionRegistry.getAllSessions(adminPrincipal,
                        false
                );

                // 如果没有session，返回不在线
                if (CollectionUtils.isEmpty(sessionInformationList)) {
                    return false;
                }

                // 如果有session,只需要找一个未过期的即可
                return sessionInformationList.stream().anyMatch(sessionInformation -> !sessionInformation.isExpired());
            }
        }
        return false;
    }

}
